package jmine.tec.extensions.impl.services;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import jmine.tec.extensions.services.ServiceExecutionRestException;
import jmine.tec.extensions.services.ServicesPageExecutorRest;
import jmine.tec.extensions.services.rs.ServiceRS;
import jmine.tec.extensions.services.rs.ServicesPageRS;
import jmine.tec.services.ServicesController;
import jmine.tec.services.api.ActionsEnum;
import jmine.tec.services.api.Service;
import jmine.tec.services.api.ServiceExecutionException;
import jmine.tec.services.api.ServiceProperties;
import jmine.tec.services.api.ServicesPage;
import jmine.tec.services.api.execution.ServicesPageExecutor;
import jmine.tec.services.api.factory.ServiceCreationException;
import jmine.tec.services.api.factory.ServiceFactory;

/**
 * @author lundberg
 */
public class ServicesPageExecutorRestImpl implements ServicesPageExecutorRest {

    private final ServicesController controller;

    private final ServiceFactory serviceFactory;

    private final ServicesPageExecutor executor;

    /**
     * Constructor
     * 
     * @param controller controller
     * @param serviceFactory serviceFactory
     * @param executor executor
     */
    public ServicesPageExecutorRestImpl(ServicesController controller, ServiceFactory serviceFactory, ServicesPageExecutor executor) {
        super();
        this.controller = controller;
        this.serviceFactory = serviceFactory;
        this.executor = executor;
    }

    /**
     * {@inheritDoc}
     */
    public void execute(List<ServicesPageRS> pages) {
        try {
            this.executor.execute(this.toServicesPage(pages));
        } catch (ServiceExecutionException e) {
            throw new ServiceExecutionRestException(e.getLocalizedMessageHolder(), e);
        }
    }

    /**
     * @param pagesRS pagesRS
     * @return list of ServicesPage
     */
    private List<ServicesPage> toServicesPage(List<ServicesPageRS> pagesRS) {
        ServiceProperties parentServiceProperties = new ServiceProperties(this.controller);
        List<ServicesPage> pages = new ArrayList<ServicesPage>();
        for (ServicesPageRS pageRS : pagesRS) {
            pages.add(this.toServicesPage(pageRS, parentServiceProperties));
        }
        return pages;
    }

    /**
     * @param pageRS pageRS
     * @param parentServiceProperties parentServiceProperties
     * @return ServicesPage
     */
    private ServicesPage toServicesPage(ServicesPageRS pageRS, ServiceProperties parentServiceProperties) {
        ServicesPage page = new ServicesPage();
        page.setName(pageRS.getName());
        for (ServiceRS serviceRS : pageRS.getServices()) {
            page.addService(this.toServiceBean(serviceRS, parentServiceProperties));
        }
        return page;
    }

    /**
     * @param serviceRS serviceRS
     * @param parentServiceProperties parentServiceProperties
     * @return service
     */
    private Service<?> toServiceBean(ServiceRS serviceRS, ServiceProperties parentServiceProperties) {
        Map<String, Object> parameters = this.controller.instantiateMap();
        parameters.putAll(serviceRS.getParameters());
        ServiceProperties serviceProperties = new ServiceProperties(this.controller, parentServiceProperties, parameters);
        try {
            return this.serviceFactory.getService(ActionsEnum.valueOf(serviceRS.getAction()), serviceRS.getName(), serviceProperties);
        } catch (ServiceCreationException e) {
            throw new ServiceExecutionRestException(e.getLocalizedMessageHolder(), e);
        }
    }

}
